#pragma once

#include <assert.h>
#include <typeinfo>

#include "Message.hpp"
#include "State.h"

namespace walker_sm
{
	template <class T>
	class FSM
	{
	public:
		FSM(T* owner)
			:owner(owner)
			,previousState(nullptr)
			,currentState(nullptr)
			,globalState(nullptr)
		{
		}

		virtual ~FSM() { }

		void Update()
		{
			if(currentState)
			{
				currentState->Excute(owner);
			}
			if(globalState)
			{
				globalState->Excute(owner);
			}
		}

		void ChangeState(State<T>* newState)
		{
			assert(newState);
			currentState->Exit(owner);
			previousState=currentState;
			currentState=newState;
			currentState->Enter(owner);
		}

		void Reverse2PreviousState()
		{
			ChangeState(previousState);
		}

		bool IsInState(State<T>* state)
		{
			return typeid(state) == typeid(currentState);
		}

		void SetPreviousState(State<T>* value) { this->previousState=value; }
		void SetCurrentState(State<T>* value) { this->currentState=value; }
		void setGlobalState(State<T>* value) { this->globalState=value; }

		State<T>* GetPreviousState() { return this->previousState; }
		State<T>* GetCurrentState() { return this->currentState; }
		State<T>* GetGlobalState() { return this->globalState; }

		bool HandleMessage(const Message& msg)
		{
			if(currentState && currentState->HandleMessage(owner,msg))
			{
				return true;
			}
			if(globalState && globalState->HandleMessage(owner,msg))
			{
				return true;
			}
			return false;
		}

	private:
		T* owner;
		State<T>* previousState;
		State<T>* currentState;
		State<T>* globalState;
	};
}

